//---------------------------------------------------------------------------------
// Copyright (c) 2008 VoiceLynx Project
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
//     1. The origin of this software must not be misrepresented; you must not
//        claim that you wrote the original software. If you use this software
//        in a product, an acknowledgment in the product documentation would be
//        appreciated but is not required.
//
//     2. Altered source versions must be plainly marked as such, and must not be
//        misrepresented as being the original software.
//
//     3. This notice may not be removed or altered from any source
//        distribution.
//---------------------------------------------------------------------------------

#ifndef __VLNet_h__
#define __VLNet_h__

#include "VLPrerequisites.h"
#include "VLENetCpp.h"
#include "VLCore.h"
#include "VLTypes.h"

//! Used by the net logic to send data in and out
//struct VLINetInterface
//{
//  ~VLINetInterface();
//
//  void sendData();
//  void receiveData();
//};


// Philosophy: For now we will assume client/server. The client always sends requests.
// The server always sends commands. The client must do what the server tells it to do.
// Any time the client wants to do something, it asks the server, then the server tells
// it to do so (which allows for the server to do all sorts of security checking and
// other verification)

// 1. The client connects to the server, possibly including a password
// 2. The server will either
//    - Send a disconnect message and kill the connection
//    - Send a connected ack
// 3. The client will request state of the server
// 4. The server will respond with a full struct of all channels and their state
// 5. The client can at any time
//    - subscribe / unsubscribe to a channel
//      - request including the channel ID
//      - server sends move packet which includes the channel's codec settings
//      - client acks new send codec settings
//    - send to a channel
//      - fire-and-forget a packet
//      - server checks the encoding used
//      - relay to all listeners (future: include a bitmask to support teams, etc.)
//    - create a channel
//      - request, sending the codec information (include autojoin flag)
//      - ack? broadcast completed?
//    - destroy a channel
//      - request, sending the channel id
//      - broadcast destroy, force those in channel to get kicked out
//    - disconnect
//      - client sends a request disconnect
//      - server tells the client to disconnect


//! Base class that all 
class VLNetBase : public VLIENetHostListener
{
public:
  VLNetBase(VLBaseCore &core);
  virtual ~VLNetBase();

  void process();

  //! Is called when we receive a packet from someone
  virtual void onPacketReceived(VLENetHostWrapper &host, ENetPeer *peer, ENetPacket &packet, enet_uint8 channel);

  //! Is called when someone connects to the host
  virtual void onConnect(VLENetHostWrapper &host, ENetPeer *peer);

  //! Is called when someone disconnects from the host
  virtual void onDisconnect(VLENetHostWrapper &host, ENetPeer *peer, enet_uint32 reason);

protected:
  virtual void closeConnections(VLEDisconnectReason reason = VL_DR_UNKNOWN);

  std::auto_ptr<VLENetHostWrapper> mHost;

  VLBaseCore &mCore;
};

class VLStandaloneClient : public VLNetBase
{
public:
  VLStandaloneClient();

  void setUsername(const VLString &username);
  void setPassword(const VLString &password);

  //! Call to connect to the server
  void connectToServer(std::string &remoteHost, short port = VL_DEFAULT_PORT);
  void disconnect() 
  { closeConnections(); }

  void onConnect(VLENetHostWrapper &host, ENetPeer *peer);
  void onDisconnect(VLENetHostWrapper &host, ENetPeer *peer, enet_uint32 reason);

  bool isConnected();

  VLClientCore &getCore() { return mCore; }

  const VLUserIdToUserMap &getUsers();

private:
  VLClientCore          mCore;
  VLClientPacketLogic  &mPacketLogic;

  std::string           mRemoteHost;
  short                 mPort;

  ENetPeer             *mServerPeer;

  bool                  mIsConnected;

  std::string           mUsername;
  std::string           mPassword;
};

class VLStandaloneServer : public VLNetBase
{
public:
  VLStandaloneServer();

  //! Call to start the server
  void beginListening(short port = VL_DEFAULT_PORT);
  
  //! Call to close the server (optionally include in the reason why the server is going down)
  void closeConnections(VLEDisconnectReason reason = VL_DR_UNKNOWN) 
  { VLNetBase::closeConnections(reason); }

  VLServerCore &getCore() { return mCore; }

private:
  VLServerCore mCore;

  VLU16 mPort;
};


typedef std::auto_ptr<VLStandaloneClient> VLNetClientPtr;
typedef std::auto_ptr<VLStandaloneServer> VLNetServerPtr;

#endif